<?php
/*
 * @Author: 杨红兵
 * @Date: 2022-08-08 11:39:07
 * @Last Modified by: 杨红兵
 * @Last Modified time: 2022-08-08 11:41:11
 */

namespace app\libraries\utils\queue\event;

use app\libraries\exception\ApiException;
use app\libraries\utils\Util;
use think\queue\Job;
use Throwable;

abstract class SyncJob
{
    /**
     * 任务数据体中的请求头
     *
     * @var array
     * @Author YangHB
     * @DateTime 2022-08-08 10:48:28
     *
     */
    protected array $headers = [];

    /**
     * 异步任务入口
     *
     * @Author YangHB
     * @DateTime 2022-08-08 10:11:47
     *
     * @param Job $job
     * @param mixed $data
     * @return void
     */
    public function fire(Job $job, $data)
    {
        $startTime = getmicrotime();
        try {
            $this->withRequest($data);
            LogInfo("job_fire", "执行Job任务-开始", "started", [
                'class' => static::class,
                'data' => $data,
            ]);

            $app = app();
            if (!is_string($data['event'])) {
                $call = $data['event'];
            } elseif (strpos($data['event'], '::')) {
                $call = $data['event'];
            } else {
                $obj  = $app->make($data['event']);
                $call = [$obj, 'handle'];
            }

            $app->invoke($call, [unserialize($data['raw']), $data['base']]);
            LogInfo("job_fire", "执行Job任务-完成", "success", ['class' => static::class]);
        } catch (Throwable $ex) {
            $retry = intval($data['retry'] ?? 0);
            $retryMax = intval($data['retryMax'] ?? 0);
            $logType = $retry < $retryMax ? "LogWarning" : "LogError";
            if (($logType == 'LogWarning' || $retryMax <= 0) && $ex instanceof ApiException) {
                $logType = 'LogInfo';
            }
            $logType('job_fire', '执行Job任务-出错', $ex->getMessage(), [
                'class' => static::class,
                'error' => Util::normalizeException($ex),
            ]);
            if ($retry < $retryMax) {
                //再次发起任务
                $data['retry'] = $retry + 1;
                $data['retryMax'] = $retryMax;
                $this->dispatch($data, ($retry + 1) * 5);
                LogInfo("job_fire", "执行Job任务-发起重试成功", "warning", [
                    'retry' => $data['retry'],
                    'retryMax' => $data['retryMax'],
                    'wait' => ($retry + 1) * 5,
                ]);
            }
        }
        $job->delete();
        LogInfo("job_fire", "执行Job任务-结束", "removed", [
            'class' => static::class,
            'useTime' => bcsub(getmicrotime(), $startTime, 6),
        ]);
    }

    /**
     * 初始当前Request
     *
     * @Author YangHB
     * @DateTime 2022-08-08 10:40:23
     *
     * @param array $data
     * @return void
     */
    protected function withRequest(&$data)
    {
        echo "withRequest s \n";
        $dataHeaders = $data['headers'] ?? [];
        $dataHeaders = array_merge($dataHeaders, [
            'REQUEST_METHOD' => 'POST',
        ]);
        /**
         * @var \think\Request
         */
        $request = app('request');
        $request->withPost($data)
            ->setMethod('POST');
        if (!empty($dataHeaders)) {
            $dataHeaders = (array)$dataHeaders;
            //设置server
            $tempServers = array_merge($request->server(), $dataHeaders);
            $request->withServer($tempServers);
            //设置header
            $tempHeaders = array_merge($request->header(), $dataHeaders);
            $request->withHeader($tempHeaders);
        } else {
            $dataHeaders = [];
        }
        $request->setRoute([]);
        $this->headers = $dataHeaders;
//        unset($data['headers']);
        echo "withRequest e \n";
    }

//    /**
//     * 实际任务处理结果，可返回
//     *
//     * @Author YangHB
//     * @DateTime 2022-08-08 10:27:30
//     *
//     * @param mixed $data
//     * @return mixed
//     */
//    public function handle($data)
//    {
//        unset($data);
//        return true;
//    }

    /**
     * 任务抛出
     *
     * @Author YangHB
     * @DateTime 2022-08-08 10:11:56
     *
     * @param  $data
     * @param int $delay
     * @return mixed
     */
    public function dispatch($data, int $delay = 0)
    {
        unset($delay);
        return app()->invoke([$this, 'handle'], $data);
    }
}
